package sortedset

import (
	"errors"
	"strconv"
	"strings"
)

type InfFlag int8

const (
	negativeInf InfFlag = -1
	finite              = 0
	positiveInf InfFlag = 1
)

// ScoreBorder is a representation of borders of numbers.
// supports:
//     normal numbers: +1., -10, 18.4
//     exclusive numbers: (+1., (-10, (18.4
//     infinite: +inf, inf, -inf
type ScoreBorder struct {
	Inf       InfFlag
	Value     float64
	Exclusive bool
}

var (
	negativeInfBorder = &ScoreBorder{Inf: negativeInf}
	positiveInfBorder = &ScoreBorder{Inf: positiveInf}
)

// LT means less than operator.
func (border ScoreBorder) LT(val float64) bool {
	if border.Inf == positiveInf {
		return false
	}
	if border.Inf == negativeInf {
		return true
	}
	return !border.Exclusive != (border.Value < val) // !exclude xor LT
}

// LE means less than or equal to operator.
func (border ScoreBorder) LE(val float64) bool {
	return !border.GT(val)
}

// GT means greater than operator.
func (border ScoreBorder) GT(val float64) bool {
	if border.Inf == positiveInf {
		return true
	}
	if border.Inf == negativeInf {
		return false
	}
	return !border.Exclusive != (border.Value > val) // !exclude xor GT
}

// GE means greater than or equal to operator.
func (border ScoreBorder) GE(val float64) bool {
	return !border.LT(val)
}

func ToScoreBorder(expr string) (*ScoreBorder, error) {
	expr = strings.ToLower(expr)
	if len(expr) <= 0 {
		return nil, errors.New("ScoreBorder expression cannot be empty")
	}
	switch expr {
	case "inf", "+inf":
		return positiveInfBorder, nil
	case "-inf":
		return negativeInfBorder, nil
	default:
		exclusive := false
		if expr[0] == '(' {
			exclusive = true
			expr = expr[1:]
		}
		if len(expr) <= 0 {
			return nil, errors.New("ScoreBorder expression cannot be empty")
		}
		value, err := strconv.ParseFloat(expr, 64)
		if err != nil {
			return nil, errors.New("ScoreBorder expression value cannot be parsed to float64")
		}
		return &ScoreBorder{
			Inf:       finite,
			Value:     value,
			Exclusive: exclusive,
		}, nil
	}
}
